package com.effectiv.gooruda.rest.service.api;

import java.util.Date;
import java.util.List;

import javax.ws.rs.DefaultValue;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.GenericEntity;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.ResponseBuilder;
import javax.ws.rs.core.Response.Status;

import jodd.util.StringUtil;
import lombok.Getter;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.dao.DataAccessException;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.CollectionCallback;

import com.effectiv.gooruda.rest.domain.Log;
import com.effectiv.gooruda.rest.ext.ExtResponse;
import com.effectiv.gooruda.rest.ext.SecurityContextHolder;

import com.mongodb.DBCollection;
import com.mongodb.MongoException;

@Path("/log")
public abstract class LogService {
	
	private final String COLLECTION_BASE = "c_app_log_";

	private final String ALLOWED_LOG_TYPES[] = { "DEBUG", "INFO", "WARN",
			"ERROR", "FATAL" };
	
	@Getter
	@Autowired
	private MongoTemplate template;

	protected void validateLogType(String type) {
		if (StringUtil.equalsOne(type, ALLOWED_LOG_TYPES) == -1) {
			
			ExtResponse extRes = new ExtResponse();
			extRes.setErrorCode(100);
			extRes.setMessage("Log type - "
					+ type
					+ " is not supported. Allowed values - DEBUG, INFO, WARN,ERROR, FATAL.");
			
			ResponseBuilder resBuilder = Response.status(Status.BAD_REQUEST);
			resBuilder.entity(extRes);
			
			throw new WebApplicationException(resBuilder.build());
		}
	}
	
	protected long countDocuments(final Query query) {
		return template.execute(getCollection(), new CollectionCallback<Long>() {

			public Long doInCollection(DBCollection collection)
					throws MongoException, DataAccessException {
				return collection.count(query.getQueryObject());
			}
		});
	}
	
	protected Response find(final Criteria criteria, int pageNo, int pageSize){
		Query query = new Query();
		query.addCriteria(criteria);
		query.skip(pageNo * pageSize);
		query.limit(pageSize);
		
		List<Log> logs = getTemplate().find(query, Log.class, getCollection());
		
		ExtResponse res = new ExtResponse();
		res.setValue(logs);
		
		if(logs == null || logs.size() == 0){
			res.setMessage("No log record found.");
		}
		
		GenericEntity<ExtResponse> entity = new GenericEntity<ExtResponse>(res, ExtResponse.class);
		
		ResponseBuilder builder = Response.ok(entity);
		
		return builder.build(); 
	}
	
	protected Response countDocuments(final Criteria criteria) {
		
		Query query = new Query();
		query.addCriteria(criteria);
		long count = countDocuments(query);
		
		ExtResponse res = new ExtResponse();
		res.setValue(count);
		
		GenericEntity<ExtResponse> entity = new GenericEntity<ExtResponse>(res, ExtResponse.class);
		
		ResponseBuilder builder = Response.ok(entity);
		
		return builder.build(); 
		
	}
	
	protected String getCollection(){
		return COLLECTION_BASE + SecurityContextHolder.get().getId();
	}
	
	@GET
	@Path("/findbetween/{start}/{end}")
	public abstract Response findBetween(@PathParam("start") Date start,
			@PathParam("end") Date end,
			@QueryParam("pageNo") @DefaultValue("0") int pageNo,
			@QueryParam("pageSize") @DefaultValue("10") int pageSize);

	@GET
	@Path("/findbytext/{text}")
	@Produces(MediaType.APPLICATION_JSON)
	public abstract Response findByText(@PathParam("text") String text,
			@QueryParam("pageNo") @DefaultValue("0") int pageNo,
			@QueryParam("pageSize") @DefaultValue("10") int pageSize);

	@POST
	@Produces(MediaType.APPLICATION_JSON)
	public abstract Response save(Log l);

	@GET
	@Path("/findbytype/{type}")
	@Produces(MediaType.APPLICATION_JSON)
	public abstract Response findByType(@PathParam("type") String type,
			@QueryParam("pageNo") @DefaultValue("0") int pageNo,
			@QueryParam("pageSize") @DefaultValue("10") int pageSize);

	@GET
	@Path("/countbytype/{type}")
	public abstract Response countByType(@PathParam("type") String type);

	@GET
	@Path("/countbytext/{text}")
	public abstract Response countByText(String text);

	@GET
	@Path("/countbydaterange/{start}/{end}")
	public abstract Response countByDateRange(Date start, Date end);
}
